﻿using System;
using EnvDTE80;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Threading;
using System.IO;

namespace MemoryLeakViewerLib
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            CommonConstructor();
        }
        
        string m_FilePath = string.Empty;
        public MainForm(DTE2 applicationObject, string FilePath)
        {
            CommonConstructor(true);

            Program.m_ApplicationObject = applicationObject;
            m_FilePath = FilePath;
        }

        void CommonConstructor(bool ShowCodeWindow = true)
        {
            InitializeComponent();

            updateTotalCountInfo(0);
            updateShownHiddenStatusInfo(0, 0);

            if (ShowCodeWindow)
            {
                Program.m_codeView = new CodeForm();
                Program.m_codeView.Show(this);
            }

            Program.m_filterForm = new FilterForm();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            LoadSettings();

            comboBox1.SelectedIndex = 0;
            comboBox2.SelectedIndex = 1;

            m_MemoryLeakCount = 0;
            m_LoadThread = new Thread(LoadThread);
            m_LoadThread.Start();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (m_LoadThread != null && m_LoadThread.IsAlive)
            {
                m_LoadThread.Abort();
            }
            SaveSettings();            
        }

        void LoadSettings()
        {
            if (!Properties.Settings.Default.FirstRun)
            {
                this.Size = Properties.Settings.Default.MainFormSize;
                this.Location = Properties.Settings.Default.MainFormLocation;

                Program.m_countFilterEnabled = Properties.Settings.Default.FilterCountEnabled;
                Program.m_countFilterValue = Properties.Settings.Default.FilterCountValue;

                if (Program.m_codeView != null)
                {
                    Program.m_codeView.Size = Properties.Settings.Default.CodeFormSize;
                    //Program.m_codeView.Location = Properties.Settings.Default.CodeFormLocation;
                }
            }
        }

        void SaveSettings()
        {
            Properties.Settings.Default.FirstRun = false;
            if (this.WindowState == FormWindowState.Normal)
            {
                Properties.Settings.Default.MainFormSize = this.Size;
                Properties.Settings.Default.MainFormLocation = this.Location;
            }
            else
            {
                Properties.Settings.Default.MainFormSize = this.RestoreBounds.Size;
                Properties.Settings.Default.MainFormLocation = this.RestoreBounds.Location;
            }

            Properties.Settings.Default.FilterCountEnabled = Program.m_countFilterEnabled;
            Properties.Settings.Default.FilterCountValue = Program.m_countFilterValue;

            if (Program.m_codeView != null)
            {
                Properties.Settings.Default.CodeFormSize = Program.m_codeView.Size;
                //Properties.Settings.Default.CodeFormLocation = Program.m_codeView.Location;
            }

            Properties.Settings.Default.Save();
        }

        // This delegate enables asynchronous calls for setting
        // the text property on a TextBox control.
        private void AddMemoryLeak(MemoryLeakItem i_Leak)
        {
            if (this.InvokeRequired)
            {
                if (IsDisposed == false)
                {
                    this.Invoke(new Action(() => AddMemoryLeak(i_Leak)));
                }
            }
            else
            {
                m_MemoryLeakCount++;
                i_Leak.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                i_Leak.Padding = new Padding(0);
                i_Leak.Margin = new Padding(0);
                flowLayoutPanel1.Controls.Add(i_Leak);
                flowLayoutPanel1.Update();
                updateTotalCountInfo(m_MemoryLeakCount);
                statusStrip1.Update();
            }
        }

        private void SetProgressMax(int i_Value)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(() => SetProgressMax(i_Value)));
            }
            else
            {
                //this.toolStripProgressBar1.Maximum = i_Value;
            }
        }

        private void SetProgress(int i_Value)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(() => SetProgress(i_Value)));
            }
            else
            {
                //this.toolStripProgressBar1.Value = i_Value;
            }
        }

        public void LoadThread()
        {
            DateTime l_StartTime = DateTime.Now;

            if (m_FilePath == string.Empty)
            {
                m_FilePath = @".\MemoryLeakReport.txt";
            }

            if (!File.Exists(m_FilePath))
            {
                return;
            }

            Program.m_ReportFileInfo = new System.IO.FileInfo(m_FilePath);

            m_MemoryLeakList = VldOutputParser.Parse(m_FilePath);

            m_MemoryLeakList.Sort(
                delegate(MemoryLeak item1, MemoryLeak item2)
                {
                    return Comparer<int>.Default.Compare(item2.GetCount(), item1.GetCount());
                });

            int l_Progress = 0;
            int l_Jump = 1;
            SetProgressMax(m_MemoryLeakList.Count);

            int hiddenCount = 0;
            int shownCount = 0;

            //this.Invoke(new Action(() => flowLayoutPanel1.SuspendLayout()));
            foreach (MemoryLeak leak in m_MemoryLeakList)
            {
                MemoryLeakItem tmp = new MemoryLeakItem(leak);

                if (Program.m_countFilterEnabled &&
                    leak.GetCount() <= Program.m_countFilterValue)
                {
                    tmp.Visible = false;
                    hiddenCount++;
                }
                else
                {
                    shownCount++;
                }

                updateShownHiddenStatusInfo(hiddenCount, shownCount);
                m_MemoryLeakItems.Add(tmp);
                this.AddMemoryLeak(tmp);
                l_Progress += l_Jump;
                SetProgress(l_Progress);
            }
            //this.Invoke(new Action(() => flowLayoutPanel1.ResumeLayout()));

            DateTime l_StopTime = DateTime.Now;
            TimeSpan l_ElapsedTime = l_StopTime - l_StartTime;
            Console.WriteLine("Elapsed: {0}", l_ElapsedTime);
            Console.WriteLine("in hours       :" + l_ElapsedTime.TotalHours);
            Console.WriteLine("in minutes     :" + l_ElapsedTime.TotalMinutes);
            Console.WriteLine("in seconds     :" + l_ElapsedTime.TotalSeconds);
            Console.WriteLine("in milliseconds:" + l_ElapsedTime.TotalMilliseconds);
        }

        private List<MemoryLeakItem> m_MemoryLeakItems = new List<MemoryLeakItem>();
        private Thread m_LoadThread;

        private void button1_Click(object sender, EventArgs e)
        {
            flowLayoutPanel1.SuspendLayout();
            foreach (MemoryLeakItem memLeak in flowLayoutPanel1.Controls)
            {
                memLeak.expand();
                //flowLayoutPanel1.Update();
            }
            flowLayoutPanel1.ResumeLayout();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            flowLayoutPanel1.SuspendLayout();
            foreach (MemoryLeakItem memLeak in flowLayoutPanel1.Controls)
            {
                memLeak.collapse();
                //flowLayoutPanel1.Update();
            }
            flowLayoutPanel1.ResumeLayout();
        }

        private void comboBoxSorting_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Thread l_SortThread = new Thread(doSorting);
            //l_SortThread.Start();
            doSorting();
        }

        private void doSorting()
        {
            if (comboBox1.SelectedItem == null ||
                comboBox2.SelectedItem == null ||
                flowLayoutPanel1.Controls.Count == 0)
            {
                return;
            }

            if (comboBox1.SelectedItem.ToString() == "Count")
            {
                if (comboBox2.SelectedItem.ToString() == "Descending")
                {
                    m_MemoryLeakItems.Sort(
                        delegate(MemoryLeakItem item1, MemoryLeakItem item2)
                        {
                            return Comparer<int>.Default.Compare(
                                item2.getMemoryLeak().GetCount(),
                                item1.getMemoryLeak().GetCount());
                        });
                }
                else
                {
                    m_MemoryLeakItems.Sort(
                        delegate(MemoryLeakItem item1, MemoryLeakItem item2)
                        {
                            return Comparer<int>.Default.Compare(
                                item1.getMemoryLeak().GetCount(),
                                item2.getMemoryLeak().GetCount());
                        });
                }
            }
            else
            {
                if (comboBox2.SelectedItem.ToString() == "Descending")
                {
                    m_MemoryLeakItems.Sort(
                        delegate(MemoryLeakItem item1, MemoryLeakItem item2)
                        {
                            return Comparer<int>.Default.Compare(
                                item2.getMemoryLeak().GetSize(),
                                item1.getMemoryLeak().GetSize());
                        });
                }
                else
                {
                    m_MemoryLeakItems.Sort(
                        delegate(MemoryLeakItem item1, MemoryLeakItem item2)
                        {
                            return Comparer<int>.Default.Compare(
                                item1.getMemoryLeak().GetSize(),
                                item2.getMemoryLeak().GetSize());
                        });
                }
            }

            flowLayoutPanel1.Controls.Clear();
            m_MemoryLeakCount = 0;
            foreach (MemoryLeakItem leakItem in m_MemoryLeakItems)
            {
                AddMemoryLeak(leakItem);
                flowLayoutPanel1.Update();
            }
        }

        private List<MemoryLeak> m_MemoryLeakList = new List<MemoryLeak>();
        int m_MemoryLeakCount = 0;

        private void button3_Click(object sender, EventArgs e)
        {
            this.Width -= 15;
        }

        //protected override void OnLayout(LayoutEventArgs e)
        //{
        //    base.OnLayout(e);
        //}

        private void flowLayoutPanel1_Layout(object sender, LayoutEventArgs e)
        {
            if (true)//e.AffectedControl == flowLayoutPanel1)
            {
                flowLayoutPanel1.Focus();
                int l_offset = 0;
                if (flowLayoutPanel1.VerticalScroll.Visible)
                    l_offset = -(SystemInformation.VerticalScrollBarWidth);

                if (flowLayoutPanel1.Controls.Count > 0)
                {
                    //Control l_Control = flowLayoutPanel1.Controls[0];

                    //bool test = flowLayoutPanel1.HorizontalScroll.Visible;
                    //flowLayoutPanel1.HorizontalScroll.Visible = false;

                    flowLayoutPanel1.SuspendLayout();
                    flowLayoutPanel1.Controls[0].Anchor = AnchorStyles.Left | AnchorStyles.Top;
                    flowLayoutPanel1.Controls[0].Width = flowLayoutPanel1.Width + l_offset;
                    flowLayoutPanel1.ResumeLayout();
                    //l_Control.Refresh();
                }
            }
        }

        private void MainForm_ResizeBegin(object sender, EventArgs e)
        {
            //SuspendLayout();
        }

        private void MainForm_ResizeEnd(object sender, EventArgs e)
        {
            //ResumeLayout();
        }

        private void MainMenuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {

        }

        private void button4_Click(object sender, EventArgs e)
        {
            DialogResult result = Program.m_filterForm.ShowDialog(this);

            if (result == System.Windows.Forms.DialogResult.OK)
            {
                int visibleCount = 0;
                int hiddenCount = 0;

                flowLayoutPanel1.SuspendLayout();

                foreach (MemoryLeakItem item in flowLayoutPanel1.Controls)
                {
                    if (Program.m_countFilterEnabled &&
                        item.getMemoryLeak().GetCount() <= Program.m_countFilterValue)
                    {
                        item.Visible = false;
                        hiddenCount++;
                    }
                    else
                    {
                        item.Visible = true;
                        visibleCount++;
                    }
                }

                flowLayoutPanel1.ResumeLayout();

                updateShownHiddenStatusInfo(hiddenCount, visibleCount);
            }
        }

        void updateTotalCountInfo(int i_numLeaks)
        {
            toolStripStatusLabel2.Text = i_numLeaks + " Memory Leaks";
        }

        void updateShownHiddenStatusInfo(int i_numHidden, int i_numShown)
        {
            toolStripStatusLabel3.Text =
                "(" + i_numHidden + " leaks hidden, " + i_numShown + " leaks shown" + ")";
        }
    }
}
